package com.cskaoyan.javse.oop2._1extends._9override;

import com.sun.xml.internal.ws.api.message.MessageWritable;

/**
 * 方法覆盖，也称之为方法的重写（override）
 * 方法的重写是继承中最核心的知识点，正是因为有了方法重写，多态才有可能，才会出现接口、抽象类、内部类这些概念。
 *
 * 在上一节一样，父子类中的成员方法也是可以同名的。
 * 那么我们直接创建子类对象，使用子类引用接收。调用同名方法，会发现访问的结果是子类中方法的行为，那么父类中的那个同名成员方法去哪了呢？
 * 还能够访问吗？首先它肯定是存在的，方法不过是方法区的二进制指令合集罢了，类加载时期，装载进方法区，不会物理消失。但"对象名点"访问成员方法这个语法还是和访问成员变量是有很大区别的， 我们可以写一个public方法，然后在方法中访问同名成员方法，最后测试调用这个public方法，发现调用结果仍然是子类中的方法。
 * 为了探究原因，我们研究一下对象名成员方法的调用机制：
 *          1.调用访问
 *          2.调用结果
 * 对象名就是一个引用,当存在继承时,有父类,有子类,这个引用可以有三种创建形式:
 *      1.子类对象用子类引用接收
 *      2.父类对象用父类对象接收
 *      3.子类对象用父类引用接收
 *
 * 首先研究调用范围：
 *      1.子类对象用子类引用接收
 *          子类自身，和它所有父类的
 *      2.父类对象用父类对象接收
 *          父类自身，和它所有父类的
 *      3.子类对象用父类引用接收
 *          父类自身，和它所有父类的
 *  综上，调用方法的范围仍然根据引用的数据类型来决定。
 *
 *  再研究调用的结果：
 *      1.子类对象用子类引用接收
 *          子类中方法的结果
 *      2.父类对象用父类对象接收
 *          父类中方法的结果
 *      3.子类对象用父类引用接收
 *          子类中方法的结果
 * 综上，对象名点成员方法的执行结果，是根据对象的具体类型来决定的，和引用是什么没有关系。
 *
 * 注意：
 *      1.方法的覆盖不是物理意义上的覆盖，只不过因为调用的机制表现为方法被覆盖了。实际上，它还是可以被访问到的，使用super关键字。
 *      2.结合我们前面封装的思想，实际开发中，大多数的成员变量都是私有化的，这意味着使用对象名点访问成员变量的机会是很罕见的，多数情况下我们都是在调用方法完成各种功能。方法的覆盖是非常重要的知识点，如果说继承是面向对象的核心，那么继承应该就属于方法的覆盖。接下来讲解方法覆盖的语法。
 *
 * @since 11:45
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 三种创建对象的方式
        /*Son s = new Son();
        s.test();
        s.invokeFatherTest();

        Father f = new Father();
        f.test();
        Father fs = new Son();
        fs.test();*/

        Son s = new Son();
        s.invokeFatherTestSuper();
    }
}

class Father {
    public void test() {
        System.out.println("father test");
    }

    public void invokeFatherTest(){
        test();
    }
    public void testFather(){
        System.out.println("father only");
    }
}

class Son extends Father {
    public void test() {
        System.out.println("son test");
    }
    public void testSon(){
        System.out.println("son only");
    }
    public void invokeFatherTestSuper(){
        super.test();
    }
}